package com.hanserwei.han_picture.utils;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.Serializer;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.hanserwei.han_picture.domain.entity.po.Picture;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.time.*;

public class KryoSerializerUtil {

    private static final ThreadLocal<Kryo> kryoThreadLocal = ThreadLocal.withInitial(() -> {
        Kryo kryo = new Kryo();
        kryo.setReferences(true);
        kryo.setRegistrationRequired(false);

        // 手动注册 Java 8 时间类的序列化器
        registerJavaTimeSerializers(kryo);

        kryo.register(Page.class);
        kryo.register(Picture.class);

        return kryo;
    });

    private static void registerJavaTimeSerializers(Kryo kryo) {
        // LocalDateTime 序列化器
        kryo.register(LocalDateTime.class, new Serializer<LocalDateTime>() {
            @Override
            public void write(Kryo kryo, Output output, LocalDateTime object) {
                output.writeString(object.toString());
            }

            @Override
            public LocalDateTime read(Kryo kryo, Input input, Class<? extends LocalDateTime> aClass) {
                return LocalDateTime.parse(input.readString());
            }

        });

        // LocalDate 序列化器
        kryo.register(LocalDate.class, new Serializer<LocalDate>() {
            @Override
            public void write(Kryo kryo, Output output, LocalDate object) {
                output.writeString(object.toString());
            }

            @Override
            public LocalDate read(Kryo kryo, Input input, Class<? extends LocalDate> type) {
                return LocalDate.parse(input.readString());
            }
        });

        // LocalTime 序列化器
        kryo.register(LocalTime.class, new Serializer<LocalTime>() {
            @Override
            public void write(Kryo kryo, Output output, LocalTime object) {
                output.writeString(object.toString());
            }

            @Override
            public LocalTime read(Kryo kryo, Input input, Class<? extends LocalTime> type) {
                return LocalTime.parse(input.readString());
            }
        });

        // Instant 序列化器
        kryo.register(Instant.class, new Serializer<Instant>() {
            @Override
            public void write(Kryo kryo, Output output, Instant object) {
                output.writeLong(object.getEpochSecond());
                output.writeInt(object.getNano());
            }

            @Override
            public Instant read(Kryo kryo, Input input, Class<? extends Instant> type) {
                long epochSecond = input.readLong();
                int nano = input.readInt();
                return Instant.ofEpochSecond(epochSecond, nano);
            }
        });

        // ZonedDateTime 序列化器
        kryo.register(ZonedDateTime.class, new Serializer<ZonedDateTime>() {
            @Override
            public void write(Kryo kryo, Output output, ZonedDateTime object) {
                output.writeString(object.toString());
            }

            @Override
            public ZonedDateTime read(Kryo kryo, Input input, Class<? extends ZonedDateTime> type) {
                return ZonedDateTime.parse(input.readString());
            }
        });

        // OffsetDateTime 序列化器
        kryo.register(OffsetDateTime.class, new Serializer<OffsetDateTime>() {
            @Override
            public void write(Kryo kryo, Output output, OffsetDateTime object) {
                output.writeString(object.toString());
            }

            @Override
            public OffsetDateTime read(Kryo kryo, Input input, Class<? extends OffsetDateTime> type) {
                return OffsetDateTime.parse(input.readString());
            }
        });

        // Duration 序列化器
        kryo.register(Duration.class, new Serializer<Duration>() {
            @Override
            public void write(Kryo kryo, Output output, Duration object) {
                output.writeString(object.toString());
            }

            @Override
            public Duration read(Kryo kryo, Input input, Class<? extends Duration> type) {
                return Duration.parse(input.readString());
            }
        });

        // Period 序列化器
        kryo.register(Period.class, new Serializer<Period>() {
            @Override
            public void write(Kryo kryo, Output output, Period object) {
                output.writeString(object.toString());
            }

            @Override
            public Period read(Kryo kryo, Input input, Class<? extends Period> type) {
                return Period.parse(input.readString());
            }
        });
    }

    public static <T> byte[] serialize(T obj) {
        if (obj == null) return null;
        try (ByteArrayOutputStream baos = new ByteArrayOutputStream();
             Output output = new Output(baos)) {
            Kryo kryo = kryoThreadLocal.get();
            kryo.writeClassAndObject(output, obj);
            output.flush();
            return baos.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException("序列化失败", e);
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> T deserialize(byte[] bytes) {
        if (bytes == null) return null;
        try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
             Input input = new Input(bais)) {
            Kryo kryo = kryoThreadLocal.get();
            return (T) kryo.readClassAndObject(input);
        } catch (Exception e) {
            throw new RuntimeException("反序列化失败", e);
        }
    }
}
